package com.wteam.dragon.model.service.impl;

import cn.hutool.core.lang.Dict;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wteam.dragon.model.mapper.MenuDtoMapper;
import com.wteam.dragon.model.mapper.MenuMapper;
import com.wteam.dragon.model.mapper.RolesMenusMapper;
import com.wteam.dragon.model.pojo.bean.Menu;
import com.wteam.dragon.model.pojo.bean.RolesMenus;
import com.wteam.dragon.model.pojo.dto.MenuDto;
import com.wteam.dragon.model.pojo.dto.RoleSmallDto;
import com.wteam.dragon.model.service.MenuService;
import com.wteam.dragon.system.basebean.bean.ResultMessage;
import com.wteam.dragon.system.exception.BadRequestException;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author 陈晓辉
 * @Date 2020/4/2 9:38
 */
@Service
@CacheConfig(cacheNames = "menu")
@RequiredArgsConstructor
public class MenuServiceImpl implements MenuService {
    private final MenuMapper menuMapper;
    private final MenuDtoMapper menuDtoMapper;
    private final RolesMenusMapper rolesMenusMapper;

    /**
     * 超级管理员
     */
    private static final String ADMIN = "admin";

    @Override
    public List<MenuDto> getMenusByRoles(List<RoleSmallDto> roles) {
        Set<Long> roleIds = roles.stream().map(RoleSmallDto::getId).collect(Collectors.toSet());
        Set<RolesMenus> rolesMenusSet = new HashSet<>();
        roleIds.forEach(roleId -> {
            QueryWrapper<RolesMenus> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(RolesMenus::getRoleId, roleId);
            rolesMenusSet.addAll(rolesMenusMapper.selectList(queryWrapper));
        });
        List<Long> menuIds = rolesMenusSet.stream().map(RolesMenus::getMenuId).collect(Collectors.toList());
        return menuDtoMapper.selectBatchIds(menuIds);
    }

    @Override
    @Cacheable(value = "menusTree")
    public ResultMessage treeMenu(List<MenuDto> menuDtoList) {
        List<MenuDto> trees = new ArrayList<>();
        Set<Long> ids = new HashSet<>();
        Collections.sort(menuDtoList);
        for (MenuDto menuDTO : menuDtoList) {
            if (menuDTO.getPid() == 0) {
                trees.add(menuDTO);
                for (MenuDto it : menuDtoList) {
                    if (it.getPid().equals(menuDTO.getId())) {
                        if (menuDTO.getChildren() == null) {
                            menuDTO.setChildren(new ArrayList<>());
                        }
                        menuDTO.getChildren().add(it);
                        ids.add(it.getId());
                    }
                }
            }
        }
        if (trees.size() == 0) {
            trees = menuDtoList.stream().filter(s -> !ids.contains(s.getId())).collect(Collectors.toList());
        }
        Dict resultMap = Dict.create()
                .set("content", trees)
                .set("totalElements", menuDtoList.size())
                .set("message", "请求成功");
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setResultParam(resultMap);
        return resultMessage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "allMenuTree", allEntries = true)
    public ResultMessage addMenu(Menu menu) {
        if (ADMIN.equals(menu.getPermission())) {
            throw new BadRequestException("权限标识不能指定为admin");
        }
        menuMapper.insert(menu);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("添加成功");
        return resultMessage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "allMenuTree", allEntries = true)
    public ResultMessage delMenu(Long menuId) {
        QueryWrapper<RolesMenus> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("menu_id", menuId);
        rolesMenusMapper.delete(queryWrapper);
        menuMapper.deleteById(menuId);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("删除成功");
        return resultMessage;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    @Caching(evict = {@CacheEvict(value = "menusTree", allEntries = true),
            @CacheEvict(value = "Authorities", allEntries = true),
            @CacheEvict(value = "allMenuTree", allEntries = true)})
    public ResultMessage editMenu(Menu menu) {
        if (ADMIN.equals(menu.getPermission())) {
            throw new BadRequestException("权限标识不能指定为admin");
        }
        if (menu.getId().equals(menu.getPid())) {
            throw new BadRequestException("上级不能为该菜单");
        }
        menuMapper.updateById(menu);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("更新成功");
        return resultMessage;
    }

    @Override
    @Cacheable(value = "allMenuTree")
    public ResultMessage treeAllMenu(String title) {
        QueryWrapper<MenuDto> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("pid", 0);
        queryWrapper.orderByAsc("sort");
        if (title != null) {
            queryWrapper.like("title", title);
        }
        List<MenuDto> menuDtoList = menuDtoMapper.selectList(queryWrapper);
        List<MenuDto> allMenuTree = treeAllMenu(menuDtoList);
        Dict resultMap = Dict.create()
                .set("message", "请求成功")
                .set("menuList", allMenuTree);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setResultParam(resultMap);
        return resultMessage;
    }

    @Override
    public List<MenuDto> treeAllMenu(List<MenuDto> menus) {
        List<MenuDto> menuDtoList = new LinkedList<>();
        menus.forEach(menuDto -> {
                    if (menuDto != null) {
                        QueryWrapper<MenuDto> queryWrapper = new QueryWrapper<>();
                        queryWrapper.eq("pid", menuDto.getId());
                        queryWrapper.orderByAsc("sort");
                        List<MenuDto> menuList = menuDtoMapper.selectList(queryWrapper);
                        if (menuList != null && menuList.size() != 0) {
                            menuDto.setChildren(treeAllMenu(menuList));
                        }
                        menuDtoList.add(menuDto);
                    }
                }
        );
        return menuDtoList;
    }
}
